package com.lagou.edu.factory;

import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AnnotationFactory {
    private static  String rootPath;
    private static Map<String ,Object> iocMap = new HashMap<>();
    private static List<String> keyNameList = new ArrayList<>();
    static {
        try {
            init();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    public static Object getBean(String beanName){
        return iocMap.get(beanName);
    }
    public static void init() throws DocumentException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        /**
         * 读取dom文件的注解，遍历
         */
        InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
        SAXReader saxReader = new SAXReader();
        Element rootElement = saxReader.read(resourceAsStream).getRootElement();
        List<Element> list = rootElement.selectNodes("//annotationScan");
        rootPath = list.get(0).attributeValue("pacakge");//com.lagou.edu
        String filePath = rootPath.replace(".", "\\");
        filePath = AnnotationFactory.class.getClassLoader().getResource("").getPath()+ filePath;
        File file = new File(filePath);//com.lagou.edu

        //遍历解析文件
        parseAnnotation(file);

        //依赖注入关系
        parseDependencyInject(iocMap);

        //增强类的方法加上代理
        parseTransactional(iocMap);
        System.out.println("获取到的iocMap"+iocMap);

    }

    private static void parseTransactional(Map<String, Object> iocMap) {
        ProxyFactroy proxyFactroy = (ProxyFactroy)iocMap.get("proxyFactroy");
        for(String keyName :keyNameList){
            Object targetObj = iocMap.get(keyName);
            Transactional annotation = targetObj.getClass().getAnnotation(Transactional.class);
            if(null!=annotation){
                Object proxy = proxyFactroy.getProxy(targetObj);
                iocMap.put(keyName,proxy);
            }
        }

    }

    private static void parseDependencyInject(Map<String, Object> iocMap) throws IllegalAccessException {
        for (String keyName : keyNameList) {
            Object parentObj = iocMap.get(keyName);
            Field[] fields = parentObj.getClass().getDeclaredFields();
            for(Field item: fields){
                item.setAccessible(true);
                Autowired a = item.getAnnotation(Autowired.class);
                Object DIObject  = iocMap.get(item.getName());
                if(null != a){
                    item.set(parentObj,DIObject);
                    iocMap.put(keyName,parentObj);
                    }
                }
            }
        }



    /**
     * 获取类的名字
     * @param file
     * @return
     */
    private static String getClassName(File file){
        String replaceName = file.getPath().replace("\\", ".");
        int comIndex = replaceName.indexOf("com");
        String substring = replaceName.substring(comIndex);
        String className = substring.substring(0,substring.indexOf(".class"));
        return className;
    }

    /**
     * 判断是否需要加入ioc
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    private static boolean needPutIoCMap(String className) throws ClassNotFoundException {
        boolean result = false;
        Annotation[] annotations = Class.forName(className).getAnnotations();
        for (Annotation annotation : annotations) {
            if(annotation.annotationType().getSimpleName().equals("Service")){
                result = true;
            }
        }
        return result;
    }

    private static void parseAnnotation(File item) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //file是目录
        if(item.isDirectory()){
            File[] files = item.listFiles();
            for(File i :files){
                parseAnnotation(i);
            }
        }
        //file是文件
        if(item.isFile()){
            if(item.getName().endsWith(".class")){
                String className = getClassName(item);//com.lagou.edu.test
                if(needPutIoCMap(className)){
                    String key = Class.forName(className).getAnnotation(Service.class).value();
                    Object o = Class.forName(className).newInstance();
                    keyNameList.add(key);
                    iocMap.put(key,o);
                }
            }
        }

    }

}
